home *** CD-ROM | disk | FTP | other *** search
- /* Output tables which say what global initializers need
- to be called at program startup, and what global destructors
- need to be called at program termination, for GNU C++ compiler.
- Copyright (C) 1987 Free Software Foundation, Inc.
- Hacked by Michael Tiemann (tiemann@mcc.com)
- COFF Changes by Dirk Grunwald (grunwald@flute.cs.uiuc.edu)
-
- This file is part of GNU CC.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing. Refer to the GNU CC General Public
- License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- GNU CC, but only under the conditions described in the
- GNU CC General Public License. A copy of this license is
- supposed to have been given to you along with GNU CC so you
- can know your rights and responsibilities. It should be in a
- file named COPYING. Among other things, the copyright notice
- and this notice must be preserved on all copies. */
-
-
- /* This file contains all the code needed for the program `collect'.
-
- `collect' is run on all object files that are processed
- by GNU C++, to create a list of all the file-level
- initialization and destruction that need to be performed.
- It generates an assembly file which holds the tables
- which are walked by the global init and delete routines.
- The format of the tables are an integer length,
- followed by the list of function pointers for the
- routines to be called.
-
- Constructors are called in the order they are laid out
- in the table. Destructors are called in the reverse order
- of the way they lie in the table. */
-
- #include "config.h"
- int target_flags; /* satisfy dependency in config.h */
-
- #ifndef USE_COLLECT
- main()
- {
- exit(0);
- }
-
- #else
-
-
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #include <stdio.h>
- #include <a.out.h>
- #include <ar.h>
-
- #ifdef UMAX
- #include <sgs.h>
- #endif
-
- /*
- * Define various output routines in terms on ASM_INT_OP,
- * which should be defined in config.h -- if it's not, add it
- * as the marker used to allocate an int on your architecture.
- */
- #ifdef i386
- #define ASM_INT_OP ASM_LONG
- #define NO_UNDERSCORES 1
- #endif
-
- #ifndef ASM_OUTPUT_INT_CONST
- #define ASM_OUTPUT_INT_CONST(FILE,VALUE) \
- fprintf(FILE,"\t%s %d\n", ASM_INT_OP, VALUE)
- #endif
-
- #ifndef ASM_OUTPUT_LABELREF_AS_INT
- #define ASM_OUTPUT_LABELREF_AS_INT(FILE,NAME) \
- (fprintf(FILE,"\t%s", ASM_INT_OP), \
- ASM_OUTPUT_LABELREF(FILE,NAME), \
- fprintf(FILE,"\n"))
- #endif
-
- #ifndef ASM_OUTPUT_PTR_INT_SUM
- #define ASM_OUTPUT_PTR_INT_SUM(FILE,NAME,VALUE) \
- (fprintf(FILE,"\t%s", ASM_INT_OP), \
- ASM_OUTPUT_LABELREF(FILE,NAME), \
- fprintf(FILE,"+%d\n", VALUE))
- #endif
-
- #ifndef ASM_OUTPUT_SOURCE_FILENAME
- #define ASM_OUTPUT_SOURCE_FILENAME(FILE,NAME)\
- fprintf (FILE, "\t.file\t\"%s\"\n", NAME);
- #endif
-
- extern int xmalloc ();
- extern void free ();
-
- #ifndef CTOR_TABLE_NAME
- #define CTOR_TABLE_NAME "__CTOR_LIST__"
- #endif
-
- #ifndef DTOR_TABLE_NAME
- #define DTOR_TABLE_NAME "__DTOR_LIST__"
- #endif
-
- /* Define or undef this in your config.h. Should be defined for
- * MIPS & Sun-386i.
- */
-
- #ifdef NO_UNDERSCORES
- # ifndef CTOR_DTOR_MARKER_NAME
- # ifndef NO_DOLLAR_IN_LABEL
- # define CTOR_DTOR_MARKER_NAME "_GLOBAL_$"
- # else
- # define CTOR_DTOR_MARKER_NAME "_GLOBAL_."
- # endif
- # define CTOR_DTOR_MARKER_LENGTH 9
- # define CTOR_DTOR_MARKER_OFFSET 0
- # endif
- #else
- # ifndef CTOR_DTOR_MARKER_NAME
- # ifndef NO_DOLLAR_IN_LABEL
- # define CTOR_DTOR_MARKER_NAME "__GLOBAL_$"
- # else
- # define CTOR_DTOR_MARKER_NAME "__GLOBAL_."
- # endif
- # define CTOR_DTOR_MARKER_LENGTH 10
- # define CTOR_DTOR_MARKER_OFFSET 1
- # endif
- #endif
-
- enum error_code { OK, BAD_MAGIC, NO_NAMELIST,
- FOPEN_ERROR, FREAD_ERROR, FWRITE_ERROR,
- RANDOM_ERROR, };
-
- enum error_code process ();
- enum error_code process_a (), process_o ();
- enum error_code output_ctor_dtor_table ();
- void assemble_name ();
-
- /* Files for holding the assembly code for table of constructor
- function pointer addresses and list of destructor
- function pointer addresses. */
- static FILE *outfile;
-
- /* Default outfile name, or take name from argv with -o option. */
- static char *outfile_name = "a.out";
-
- /* For compatibility with toplev.c and tm-sun386.h */
- char *dump_base_name;
- int optimize = 0;
- char *language_string = "GNU C++";
- char *main_input_filename;
-
- /*
- * The list of constructors & destructors. We process all files & then
- * spit these out in output_ctor_dtor_table(), because we need to know
- * the length of the list.
- */
-
- struct ctor_dtor_list_elem
- {
- struct ctor_dtor_list_elem *next;
- char *name;
- } *dtor_chain, *ctor_chain;
-
- int dtor_chain_length = 0;
- int ctor_chain_length = 0;
-
- main (argc, argv)
- int argc;
- char *argv[];
- {
- int i, nerrs = 0;
- enum error_code code;
- FILE *fp;
-
- if (argc > 2 && !strcmp (argv[1], "-o"))
- {
- outfile_name = argv[2];
- i = 3;
- }
- else
- i = 1;
-
- if ((outfile = fopen (outfile_name, "w")) == NULL)
- {
- perror ("collect");
- exit (-1);
- }
-
- dump_base_name = main_input_filename = outfile_name;
- for (; i < argc; i++)
- {
- char buf[80];
-
- /* This is a library, skip it. */
- if (argv[i][0] == '-' && argv[i][1] == 'l')
- continue;
-
- if ((fp = fopen (argv[i], "r")) == NULL)
- {
- sprintf (buf, "collect `%s'", argv[i]);
- perror (buf);
- exit (-1);
- }
-
- switch (code = process (fp, argv[i]))
- {
- case OK:
- break;
-
- case BAD_MAGIC:
- fprintf (stderr, "file `%s' has a bad magic number for collect\n",
- argv[i]);
- exit (-1);
-
- case NO_NAMELIST:
- fprintf (stderr, "file `%s' has a no namelist for collect\n",
- argv[i]);
- exit (-1);
-
- case RANDOM_ERROR:
- fprintf (stderr, "random error while processing file `%s':\n",
- argv[i]);
- perror ("collect");
- exit (-1);
-
- case FOPEN_ERROR:
- fprintf (stderr, "fopen(3S) error while processing file `%s' in collect\n",
- argv[i]);
- exit (-1);
-
- case FREAD_ERROR:
- fprintf (stderr, "fread(3S) error while processing file `%s' in collect\n",
- argv[i]);
- exit (-1);
-
- case FWRITE_ERROR:
- fprintf (stderr, "fwrite(3S) error while processing file `%s' in collect\n",
- argv[i]);
- exit (-1);
-
- default:
- abort ();
- }
-
- fclose (fp);
-
- }
-
- switch (code = output_ctor_dtor_table ())
- {
- case OK:
- fclose (outfile);
- exit (0);
- case FREAD_ERROR:
- perror ("fread(3S) failed in collect, at end");
- break;
- case FWRITE_ERROR:
- perror ("fwrite(3S) failed in collect, at end");
- break;
- case FOPEN_ERROR:
- perror ("fopen(3S) failed in collect, at end");
- break;
- case RANDOM_ERROR:
- fprintf (stderr, "random error in collect, at end");
- break;
- }
- exit (-1);
- }
-
- void
- add_ctor_dtor_elem(symbol_name)
- char *symbol_name;
- {
- /*
- * In EXTENDED_COFF systems, it's possible to
- * have multiple occurances of symbols ( or so it
- * appears) in the symbol table. Sooo, we scan to
- * eliminate duplicate entries. This can never hurt,
- * and helps EXTENDED_COFF.
- */
- int exists;
- int is_ctor = (symbol_name[CTOR_DTOR_MARKER_LENGTH] == 'I');
-
- struct ctor_dtor_list_elem *p
- = ((is_ctor) ? ctor_chain : dtor_chain);
-
- exists = 0;
- while (p) {
- if (strcmp( symbol_name, p -> name ) == 0 ) {
- exists = 1;
- break;
- }
- p = p -> next;
- }
- if ( ! exists ) {
-
- struct ctor_dtor_list_elem *new = (struct ctor_dtor_list_elem *)
- xmalloc(sizeof(struct ctor_dtor_list_elem));
-
- new->name = (char *)xmalloc (strlen (symbol_name)
- + CTOR_DTOR_MARKER_OFFSET + 2);
-
- strcpy(new -> name, symbol_name + CTOR_DTOR_MARKER_OFFSET);
-
- if ( is_ctor ) {
- new -> next = ctor_chain;
- ctor_chain = new;
- ctor_chain_length++;
- }
- else {
- new->next = dtor_chain;
- dtor_chain = new;
- dtor_chain_length++;
- }
- }
- }
-
-
- enum error_code
- output_ctor_dtor_table ()
- {
- int dtor_offset;
-
- /* Write out the CTOR tabel */
- ASM_FILE_START(outfile);
-
- fprintf (outfile, "%s\n", TEXT_SECTION_ASM_OP);
- ASM_GLOBALIZE_LABEL (outfile, CTOR_TABLE_NAME);
- ASM_OUTPUT_LABEL (outfile, CTOR_TABLE_NAME);
- ASM_OUTPUT_INT_CONST(outfile,ctor_chain_length);
- while ( ctor_chain ) {
- ASM_OUTPUT_LABELREF_AS_INT (outfile, ctor_chain->name);
- ctor_chain = ctor_chain -> next;
- }
- /* NULL-terminate the list of constructors. -- not needed, but keep it */
- ASM_OUTPUT_INT_CONST (outfile, 0);
-
- /*
- * Now, lay out the destructors
- */
-
- fprintf (outfile, "%s\n", DATA_SECTION_ASM_OP);
- ASM_GLOBALIZE_LABEL (outfile, DTOR_TABLE_NAME);
- ASM_OUTPUT_LABEL (outfile, DTOR_TABLE_NAME);
- ASM_OUTPUT_INT_CONST(outfile,dtor_chain_length);
- while (dtor_chain)
- {
- ASM_OUTPUT_LABELREF_AS_INT (outfile, dtor_chain->name);
- dtor_chain = dtor_chain->next;
- }
- ASM_OUTPUT_INT_CONST (outfile, 0);
- ASM_OUTPUT_INT_CONST (outfile, 0);
-
- fclose (outfile);
- return OK;
- }
-
-
- /*****************************************************************************
- *
- * COFF & EXTENDED COFF
- *
- ****************************************************************************/
- #if defined(COFF) || defined(EXTENDED_COFF)
-
- #include <ldfcn.h>
-
- #if defined(EXTENDED_COFF)
- # define GCC_SYMBOLS(X) (SYMHEADER(X).isymMax+SYMHEADER(X).iextMax)
- # define GCC_SYMENT SYMR
- # define GCC_OK_SYMBOL(X) ((X).st == stProc && (X).sc == scText)
- # define GCC_SYMINC(X) (1)
- #else
- # define GCC_SYMBOLS(X) (HEADER(ldptr).f_nsyms)
- # define GCC_SYMENT SYMENT
- #ifndef UNUSUAL_COFF_DEFINITION
- # define GCC_OK_SYMBOL(X) (!(((X).n_type & N_TMASK) != (DT_NON << N_BTSHFT)))
- #else
- # define GCC_OK_SYMBOL(X) ((X).n_scnum == 1 && (X).n_sclass == C_EXT)
- #endif
- # define GCC_SYMINC(X) ((X).n_numaux+1)
- #endif
-
- enum error_code
- process (fp, filename)
- FILE *fp;
- char *filename;
- {
- LDFILE *ldptr = NULL;
- do {
- if ((ldptr = ldopen(filename, ldptr)) != NULL ) {
-
- if (!ISCOFF( HEADER(ldptr).f_magic ) ) {
- return BAD_MAGIC;
- }
- else {
-
- int symbols = GCC_SYMBOLS(ldptr);
- int symindex;
-
- for (symindex = 0;
- symindex < symbols;
- ) {
-
- GCC_SYMENT symbol;
-
- char *symbol_name;
- extern char *ldgetname();
- int returnCode;
-
- returnCode = ldtbread(ldptr, symindex, &symbol);
-
- if ( returnCode <= 0 ) {
- break;
- }
-
- symindex += GCC_SYMINC(symbol);
-
- if (! GCC_OK_SYMBOL(symbol)) continue;
- symbol_name = ldgetname(ldptr, &symbol);
-
- /* Check to see if we have a CTOR/DTOR marker */
-
- if (! strncmp (CTOR_DTOR_MARKER_NAME, symbol_name,
- CTOR_DTOR_MARKER_LENGTH))
- add_ctor_dtor_elem(symbol_name);
- }
- }
- }
- else {
- return( RANDOM_ERROR );
- }
- } while ( ldclose(ldptr) == FAILURE ) ;
- return ( OK );
- }
-
- /****** taken from sdbout.c ******/
-
-
- /* Tell the assembler the source file name.
- On systems that use SDB, this is done whether or not -g,
- so it is called by ASM_FILE_START.
-
- ASM_FILE is the assembler code output file,
- INPUT_NAME is the name of the main input file. */
-
- /* void */
- sdbout_filename (asm_file, input_name)
- FILE *asm_file;
- char *input_name;
- {
- int len = strlen (input_name);
- char *na = input_name + len;
-
- /* NA gets INPUT_NAME sans directory names. */
- while (na > input_name)
- {
- if (na[-1] == '/')
- break;
- na--;
- }
-
- ASM_OUTPUT_SOURCE_FILENAME (asm_file, na);
- }
-
- #else
-
- /*****************************************************************************
- *
- * BSD SYMBOL TABLES
- *
- *****************************************************************************/
-
- /* Figure out the type of file we need to process.
- Currently, only .o and .a formats are acceptable. */
- enum error_code
- process (fp, filename)
- FILE *fp;
- char *filename;
- {
- struct stat file_stat;
- union
- {
- char ar_form[SARMAG];
- struct exec a_out_form;
- } header;
- int size;
-
- if (fstat (fp->_file, &file_stat))
- return RANDOM_ERROR;
-
- size = file_stat.st_size;
-
- if (fread (header.ar_form, SARMAG, 1, fp) < 1)
- return RANDOM_ERROR;
-
- if (strncmp (ARMAG, header.ar_form, SARMAG))
- {
- fseek (fp, 0, 0);
- if (fread (&header.a_out_form, sizeof (struct exec), 1, fp) < 1)
- return RANDOM_ERROR;
-
- if (N_BADMAG (header.a_out_form))
- return BAD_MAGIC;
-
- return process_o (fp, &header.a_out_form, size);
- }
- return process_a (fp);
- }
-
- enum error_code
- process_o (fp, header, size)
- FILE *fp;
- struct exec *header;
- int size;
- {
- int symoff, symend;
- #ifndef hp9000s300
- struct nlist *nelem, *nelems, *nend;
- char *strtab;
- #else
- struct nlist_ *nelem, *nelems, *nend;
- #endif /* hp9000s300 */
-
- if (N_BADMAG (*header))
- return BAD_MAGIC;
-
- #ifndef hp9000s300
- symoff = N_SYMOFF (*header);
- symend = N_STROFF (*header);
- #else
- symoff = LESYM_OFFSET (*header);
- symend = DNTT_OFFSET (*header);
- #endif /* hp9000s300 */
- if (symoff == symend)
- return NO_NAMELIST;
- fseek (fp, symoff - sizeof (struct exec), 1);
- #ifndef hp9000s300
- nelems = (struct nlist *)alloca (symend - symoff);
- #else
- nelems = (struct nlist_ *)alloca (symend - symoff);
- #endif /* hp9000s300 */
- if (fread (nelems, sizeof (char), symend - symoff, fp) < symend - symoff)
- return FREAD_ERROR;
-
- #ifndef hp9000s300
- strtab = (char *)alloca ((char *)size - (char *)symend);
- if (fread (strtab, sizeof (char), (char *)size - (char *)symend, fp)
- < ((char *)size - (char *)symend) * sizeof (char))
- return FREAD_ERROR;
-
- nend = (struct nlist *)((char *)nelems + symend - symoff);
- for (nelem = nelems; nelem < nend; nelem++)
- #else
- nend = (struct nlist_ *)((char *)nelems + symend - symoff);
- for (nelem = nelems; nelem < nend; )
- #endif /* hp9000s300 */
- {
- #ifndef hp9000s300
- int strindex = nelem->n_un.n_strx;
- #else
- int symlen = nelem->n_length;
- char p[255];
- memcpy(p, (char *) (++nelem), symlen);
- p[symlen]='\0';
-
- /* printf("'%s'\n",p); */
- #endif /* hp9000s300 */
-
- #ifndef hp9000s300
- if (strindex)
- #else
- nelem = (struct nlist_ *)((char *)nelem + symlen);
-
- if (symlen)
- #endif /* hp9000s300 */
- {
- #ifndef hp9000s300
- char *p = strtab+strindex;
- #endif /* hp9000s300 */
-
- if (! strncmp ("__GLOBAL_$", p, 10))
- add_ctor_dtor_elem(p);
- }
- }
- return OK;
- }
-
- enum error_code
- process_a (fp)
- FILE *fp;
- {
- struct ar_hdr header;
- struct exec exec_header;
- int size;
- enum error_code code;
-
- while (! feof (fp))
- {
- char c;
- #ifdef hp9000s300
- int curpos;
- #endif /* hp9000s300 */
-
- if (fread (&header, sizeof (struct ar_hdr), 1, fp) < 1)
- return RANDOM_ERROR;
-
- size = atoi (header.ar_size);
- #ifdef hp9000s300
- curpos = ftell(fp);
- #endif /* hp9000s300 */
-
- #ifndef hp9000s300
- if (fread (&exec_header, sizeof (struct exec), 1, fp) < 1)
- return RANDOM_ERROR;
- #else
- /* if the name starts with /, it's an index file */
- if (header.ar_name[0] != '/') {
-
- if (fread (&exec_header, sizeof (struct exec), 1, fp) < 1)
- return RANDOM_ERROR;
- #endif /* hp9000s300 */
-
- code = process_o (fp, &exec_header, size);
- if (code != OK)
- return code;
- #ifdef hp9000s300
- }
-
- if (fseek(fp,(long) curpos + size,0))
- return RANDOM_ERROR;
- #endif /* hp9000s300 */
- if ((c = getc (fp)) == '\n')
- ;
- else
- ungetc (c, fp);
- c = getc (fp);
- if (c != EOF)
- ungetc (c, fp);
- }
- return OK;
- }
- #endif
-
- /* Output to FILE a reference to the assembler name of a C-level name NAME.
- If NAME starts with a *, the rest of NAME is output verbatim.
- Otherwise NAME is transformed in an implementation-defined way
- (usually by the addition of an underscore).
- Many macros in the tm file are defined to call this function.
-
- Swiped from `varasm.c' */
-
- void
- assemble_name (file, name)
- FILE *file;
- char *name;
- {
- if (name[0] == '*')
- fputs (&name[1], file);
- else
- #ifdef NO_UNDERSCORES
- fprintf (file, "%s", name);
- #else
- fprintf (file, "_%s", name);
- #endif
- }
-
- int
- xmalloc (size)
- int size;
- {
- int result = malloc (size);
- if (! result)
- {
- fprintf (stderr, "Virtual memory exhausted\n");
- exit (-1);
- }
- return result;
- }
- #endif
-